package com.pig4cloud.pig.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.admin.api.entity.MetaEntityEntity;
import com.pig4cloud.pig.admin.api.entity.MetaFieldEntity;
import com.pig4cloud.pig.admin.entity.Field;
import com.pig4cloud.pig.admin.entity.vo.TabulateVO;
import com.pig4cloud.pig.admin.enums.BaseFieldType;
import com.pig4cloud.pig.admin.mapper.CommonMapper;
import com.pig4cloud.pig.admin.service.CommonService;
import com.pig4cloud.pig.admin.service.MetaEntityService;
import com.pig4cloud.pig.admin.service.MetaFieldService;
import com.pig4cloud.pig.common.core.constant.CommonConstants;
import com.pig4cloud.pig.common.core.constant.enums.OperatorEnum;
import com.pig4cloud.pig.common.core.constant.enums.SqlMethod;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.mybatis.base.Group;
import com.pig4cloud.pig.flow.api.dto.StartFlowDTO;
import com.pig4cloud.pig.flow.api.dto.SuspensionDTO;
import com.pig4cloud.pig.flow.api.feign.RemoteFlowService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author mobai
 */
@Service
@Slf4j
public class CommonServiceImpl extends ServiceImpl<CommonMapper, Map<String, Object>> implements CommonService {
	private final MetaEntityService metaEntityService;
	private final MetaFieldService metaFieldService;

	private final RemoteFlowService remoteFlowService;

	public CommonServiceImpl(@Lazy MetaEntityService metaEntityService, @Lazy MetaFieldService metaFieldService, RemoteFlowService remoteFlowService) {
		this.metaEntityService = metaEntityService;
		this.metaFieldService = metaFieldService;
		this.remoteFlowService = remoteFlowService;
	}

	@Override
	public void createBaseEntity(String tableName) {
		baseMapper.createBaseEntity(tableName);

	}

	@Override
	public void addTableField(String tableName, Field field) {
		baseMapper.addTableField(tableName, field);
	}

	@Override
	public void removeTableField(String tableName, String fieldName) {
		baseMapper.removeTableField(tableName, fieldName);
	}


	@Override
	public R getMetaFieldList(String label) {
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		List<MetaFieldEntity> fieldList = metaEntity.getMetaFieldList();
		Map<String, MetaFieldEntity> fieldNameMap = getFieldNameList(metaEntity.getFormJson().getBaseShowFieldList(), fieldList);
		List<Group> conditions = metaEntity.getFormJson().getGroupsConditions();

		Map<String, MetaFieldEntity> searchFieldMap = getFieldNameList(getFieldNameList(conditions), fieldList);


		//根据field的order进行倒排序
		TabulateVO tabulateVO = new TabulateVO();
		tabulateVO.setShowFields(fieldNameMap.values().stream().sorted(Comparator.comparing(MetaFieldEntity::getOrder).reversed()).toList());
		tabulateVO.setSearchFields(searchFieldMap.values());
		return R.ok(tabulateVO);
	}

	private List<String> getFieldNameList(List<Group> conditions) {
		List<String> fieldNameList = new ArrayList<>();
		if (ObjectUtil.isEmpty(conditions)) {
			return fieldNameList;
		}

		conditions.forEach(group -> {
			group.getConditions().forEach(condition -> {
				fieldNameList.add(condition.getField());
			});
			fieldNameList.addAll(getFieldNameList(group.getGroups()));
		});
		return fieldNameList;
	}


	/**
	 * 通用查询数据接口
	 *
	 * @param page
	 * @param params
	 * @return
	 */
	@Override
	public R getMetaEntityPage(Page page, Map<String, Object> params, String label) {
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		List<MetaFieldEntity> fieldList = metaEntity.getMetaFieldList();
		String condition = buildCondition(metaEntity.getPhysicalName(), metaEntity.getFormJson().getGroupsConditions(), fieldList.stream().collect(Collectors.toMap(MetaFieldEntity::getLabel, s -> s)), params);
		return R.ok(baseMapper.queryPage(page, metaEntity.getPhysicalName(), fieldList.stream().map(MetaFieldEntity::getPhysicalName).toList(), condition, params));
	}


	/**
	 * 根据实体id获取详情
	 *
	 * @param label
	 * @param id
	 * @return
	 */
	@Override
	public R getDetails(String label, String id) {
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		List<MetaFieldEntity> fieldList = metaEntity.getMetaFieldList();
		return R.ok(baseMapper.getDetails(metaEntity.getPhysicalName(), id, fieldList.stream().map(MetaFieldEntity::getPhysicalName).toList()));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R addTableData(String label, Map<String, Object> params) {
		if (ObjectUtil.isEmpty(params)) {
			return R.ok();
		}
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		metaEntity.setMetaFieldList(metaFieldService.list(Wrappers.lambdaQuery(MetaFieldEntity.class).eq(MetaFieldEntity::getEntityId, metaEntity.getId())));
		List<MetaFieldEntity> fieldList = metaEntity.getMetaFieldList();
		setBaseField(params);
		List<String> nameList = params.keySet().stream().toList();
		Map<String, MetaFieldEntity> fieldNameList = getFieldNameList(nameList, fieldList);
		String insertSql;
		try {
			insertSql = buildInsertSql(metaEntity.getPhysicalName(), fieldNameList.values(), params);
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
		if (ObjectUtil.isEmpty(insertSql)) {
			return R.ok();
		}
		baseMapper.insertTableData(insertSql, params);
//		CompletableFuture.runAsync(() -> {

		if (ObjectUtil.equal(CommonConstants.YES.toString(), metaEntity.getFlowStatus()) && ObjectUtil.equal(CommonConstants.YES.toString(), metaEntity.getAutoStartFlow())) {
			R<String> e = saveProcessInstanceId(params, metaEntity);
			if (e != null) {
				return e;
			}
		}
//		});


		return R.ok();
	}

	@Nullable
	private R<String> saveProcessInstanceId(Map<String, Object> params, MetaEntityEntity metaEntity) {
		R<String> flow;
		try {
			flow = remoteFlowService.startProcessInstance(new StartFlowDTO() {{
				setFlowKey(metaEntity.getFlowKey());
				setParams(params);
			}});
		} catch (Exception e) {
			log.error("流程启动异常：{}", e.getMessage());
			return R.failed(e.getMessage());
		}
		if (CommonConstants.FAIL.equals(flow.getCode())) {
			log.error("流程启动失败：{}", flow.getMsg());
			return R.failed(flow.getMsg());
		}
		baseMapper.setProcessInstanceId(metaEntity.getPhysicalName(), params.get(BaseFieldType.ID.getLabel()), flow.getData());
		return null;
	}


	@Override
	public R startFlow(String label, String id) {
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		// 获取数据
		Map<String, Object> params = baseMapper.getDetails(metaEntity.getPhysicalName(), id, metaEntity.getMetaFieldList().stream().map(MetaFieldEntity::getPhysicalName).toList());
		if (ObjectUtil.equal(CommonConstants.YES.toString(), metaEntity.getFlowStatus()) && ObjectUtil.isEmpty(params.get(BaseFieldType.PROCESS_INSTANCE_ID.getLabel()))) {
			R<String> e = saveProcessInstanceId(params, metaEntity);
			if (e != null) {
				return e;
			}
		}
		return R.ok();
	}

	@Override
	public R updateEntityById(String label, Map<String, Object> params) {
		MetaEntityEntity metaEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntity)) {
			return R.failed("实体不存在");
		}
		List<String> nameList = params.keySet().stream().toList();
		// 检验字段是否存在
		Map<String, MetaFieldEntity> fieldNameList = getFieldNameList(nameList, metaEntity.getMetaFieldList());

		String updateSql;
		try {
			updateSql = buildUpdateSql(metaEntity.getPhysicalName(), fieldNameList.values(), params);
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}

		if (ObjectUtil.isEmpty(updateSql)) {
			return R.ok();
		}

		return R.ok(baseMapper.updateEntityById(updateSql, params));
	}


	@Override
	public R removeDataById(String label, Long[] ids) {
		MetaEntityEntity metaEntityEntity = getMetaEntityEntity(label);
		if (ObjectUtil.isNull(metaEntityEntity)) {
			return R.failed("实体不存在");
		}
		if (ObjectUtil.isEmpty(ids)) {
			return R.failed("id不能为空");
		}
		// 根据ids获取所有的流程数据
//		CompletableFuture.runAsync(() -> {
		List<String> processInstanceIdList = baseMapper.queryProcessInstanceIdByIdList(metaEntityEntity.getPhysicalName(), ids);
		processInstanceIdList.forEach(processInstanceId -> {
			remoteFlowService.updateSuspendState(new SuspensionDTO() {{
				setProcessInstanceId(processInstanceId);
				setSuspensionStatus(true);
			}});
		});
//		});
		return R.ok(baseMapper.removeDataById(metaEntityEntity.getPhysicalName(), ids));
	}

	private String buildUpdateSql(String tableName, Collection<MetaFieldEntity> fieldEntities, Map<String, Object> params) {
		if (ObjectUtil.isEmpty(params.get(BaseFieldType.ID.getLabel()))) {
			throw new RuntimeException("id不能为空");
		}
		List<String> fieldNameList = new ArrayList<>();
		for (MetaFieldEntity fieldEntity : fieldEntities) {
			if (ObjectUtil.equal(fieldEntity.getSystemFieldFlag(), CommonConstants.YES) || ObjectUtil.equal(fieldEntity.getUpdatable(), CommonConstants.NO)) {
				continue;
			}
			fieldNameList.add(fieldEntity.getPhysicalName());
			if (ObjectUtil.equal(fieldEntity.getNullable(), CommonConstants.NO) && ObjectUtil.isNull(params.get(fieldEntity.getPhysicalName()))) {
				throw new RuntimeException("字段" + fieldEntity.getName() + "不允许为空");
			}
		}

		if (fieldNameList.isEmpty()) {
			return "";
		}
		// 使用模板字符串构建插入SQL语句
		return String.format(SqlMethod.UPDATE.getSql(),
				tableName,
				fieldNameList.stream().map(fieldName -> fieldName + "=#{params." + fieldName + "}").collect(Collectors.joining(",")),
				"id=#{params.id}"
		);
	}

	private void setBaseField(Map<String, Object> params) {
		for (BaseFieldType fieldType : BaseFieldType.values()) {
			params.put(fieldType.getLabel(), fieldType.getDefaultValue().get());
		}
	}

	/**
	 * 构建插入SQL语句
	 *
	 * @param tableName     表名
	 * @param fieldEntities 字段名及其元数据信息的映射
	 * @return 构建好的插入SQL语句
	 */
	private String buildInsertSql(String tableName, Collection<MetaFieldEntity> fieldEntities, Map<String, Object> params) {
		List<String> fieldNameList = new ArrayList<>();
		for (MetaFieldEntity fieldEntity : fieldEntities) {
			if (ObjectUtil.equal(fieldEntity.getSystemFieldFlag(), CommonConstants.NO) && !ObjectUtil.equal(fieldEntity.getCreatable(), CommonConstants.YES)) {
				continue;
			}
			boolean empty = ObjectUtil.isEmpty(params.get(fieldEntity.getPhysicalName()));
			if (ObjectUtil.equal(fieldEntity.getNullable(), CommonConstants.NO) && empty) {
				throw new RuntimeException("字段" + fieldEntity.getName() + "不允许为空");
			}
			if (empty) {
				continue;
			}

			fieldNameList.add(fieldEntity.getPhysicalName());
		}

		if (fieldNameList.isEmpty()) {
			return "";
		}
		// 使用模板字符串构建插入SQL语句
		return String.format(SqlMethod.INSERT.getSql(),
				tableName,
				String.join(",", fieldNameList),
				fieldNameList.stream().map(fieldName -> "#{params." + fieldName + "}").collect(Collectors.joining(",")));
	}


	private MetaEntityEntity getMetaEntityEntity(String label) {
		MetaEntityEntity metaEntity = metaEntityService.getOne(Wrappers.lambdaQuery(MetaEntityEntity.class).eq(MetaEntityEntity::getLabel, label));
		if (ObjectUtil.isNull(metaEntity)) {
			return null;
		}
		metaEntity.setMetaFieldList(metaFieldService.list(Wrappers.lambdaQuery(MetaFieldEntity.class).eq(MetaFieldEntity::getEntityId, metaEntity.getId())));
		return metaEntity;
	}


	/**
	 * 构建SQL查询条件
	 *
	 * @param tableName  数据表名
	 * @param conditions 字段条件对象，包含操作类型和字段条件列表
	 * @param fieldMap   字段列表，用于查找字段信息
	 * @param params     查询参数，键值对形式，键为字段名，值为查询值
	 * @return 构建的SQL查询条件字符串
	 */
	private String buildCondition(String tableName, List<Group> conditions, Map<String, MetaFieldEntity> fieldMap, Map<String, Object> params) {
		// 如果参数对象为空，则直接返回空字符串
		if (ObjectUtil.isEmpty(params)) {
			return "";
		}
		if (ObjectUtil.isEmpty(conditions)) {
			return "";
		}
		String sql = "";

		for (Group group : conditions) {
			OperatorEnum groupOperatorEnum = OperatorEnum.getByType(group.getOperator());
			List<String> sqlList = new ArrayList<>();
			group.getConditions().forEach(condition -> {
				if (ObjectUtil.isEmpty(params.get(condition.getField()))) {
					return;
				}
				// 根据条件对象中的操作类型获取对应的操作枚举
				OperatorEnum operatorEnum = OperatorEnum.getByType(condition.getOperator());
				if (ObjectUtil.isNull(operatorEnum)) {
					return;
				}
				MetaFieldEntity metaFieldEntity = fieldMap.get(condition.getField());
				if (ObjectUtil.isEmpty(metaFieldEntity)) {
					return;
				}
				sqlList.add(String.format(operatorEnum.getSqlValue(), tableName + "." + metaFieldEntity.getPhysicalName(), condition.getField()));
			});
			if (sqlList.isEmpty()) {
				return "";
			}
			sql = sqlList.stream().collect(Collectors.joining(groupOperatorEnum.getSqlValue(), "(", ")"));
			String s = buildCondition(tableName, group.getGroups(), fieldMap, params);
			if (ObjectUtil.isNotEmpty(s)) {
				sql = sql + groupOperatorEnum + s;
			}
		}
		return sql;
	}

	/**
	 * 字段名校验
	 *
	 * @param nameList
	 * @param fieldList
	 * @return
	 */
	private Map<String, MetaFieldEntity> getFieldNameList(List<String> nameList, List<MetaFieldEntity> fieldList) {
		List<MetaFieldEntity> list = fieldList.stream().filter(field -> nameList.contains(field.getPhysicalName())).toList();
		return list.stream().collect(Collectors.toMap(MetaFieldEntity::getPhysicalName, s -> s));
	}


}
